# ----
# ES Standard Imports
# ----
from es import load as sload, unload as sunload, AddonInfo, exists, playsound, ServerVar, event, loadevents, createentity, getindexprop, server
from cmdlib import registerSayCommand, unregisterSayCommand, registerClientCommand, unregisterClientCommand
from playerlib import getPlayer
from popuplib import easymenu
from random import choice, shuffle, sample, randint

# ----
# Custom Librarys Imports
# ----
import libs
reload(libs)

from libs.dataList import readData
from libs.diceConfigs import configFile
from libs.playerStrings import stringsManager
from libs.playerExtras import getPlayer as egetPlayer

# ----
# Addon Information
# ----
info = AddonInfo()
info.name = 'SuperDice'
info.version = '0.0.4 RV3'
info.basename = 'superdice'
info.url = 'http://addons.eventscripts.com/addons/view/superdice'
info.author = 'MiB'

# ----
# Callables
# ----
class fakeDict(dict):
    def __getitem__(self, attr):
        if not attr in self:
            self[attr] = 0

        return dict.__getitem__(self, attr)

class Players(dict):
    def __getitem__(self, attr):
        if not attr in self:
            self[attr] = fakeDict()

        return dict.__getitem__(self, attr)

players = Players()

def fireEvent(name, args):
    event('initialize', name)
    for arg in args:
        event('setstring', name, arg, args[arg])

    event('fire', name)

def getGameTime():
    # Thanks L'In20Cible!
    index = createentity('env_particlesmokegrenade')
    time = getindexprop(index, 'ParticleSmokeGrenade.m_flSpawnTime')
    server.queuecmd('es_xremove ' + str(index))
    return time

def registerRoll(callback, name):
    callbacks[callback] = name

def unregisterRoll(callback):
    del callbacks[callback]

def registerAbility(plus, minus):
    acallbacks['plus'].add(plus)
    acallbacks['minus'].add(minus)

def unregisterAbility(plus, minus):
    acallbacks['plus'].discard(plus)
    acallbacks['minus'].discard(minus)

# ----
# Callbacks
# ----
def plusAbilityCallback(userid, args):
    if not acallbacks['plus']:
        return

    for callback in acallbacks['plus']:
        callback(userid, args)

def minusAbilityCallback(userid, args):
    if not acallbacks['minus']:
        return

    for callback in acallbacks['minus']:
        callback(userid, args)

def rollCallback(userid, args):
    userid = str(userid)
    if not userid in players:
        players[userid]['rolls'] = 0

    if callbacks:
        player = getPlayer(userid)
        eplayer = egetPlayer(userid)
        if not player.isdead:
            if players[userid]['rolls'] < int(rollAmount):
                players[userid]['rolls'] += 1
                if randint(0, 100) > int(rollFail):
                    keys = callbacks.keys()
                    shuffle(keys)
                    callback = choice(sample(keys, len(keys)))
                    callback(userid, player, eplayer)
                    playsound(userid, 'ambient/office/coinslot1.wav', 1.0)
                    fireEvent('player_roll_success', {'userid':userid, 'roll':callbacks[callback]})
                    for target in players:
                        if userid == target:
                            strings.tellString(target, 'rolledname', {'roll':rollStrings.getString(userid, callbacks[callback] + ':name', {})})
                            strings.tellString(target, 'rolleddesc', {'description':rollStrings.getString(userid, callbacks[callback] + ':desc', {})})

                        else:
                            if int(announceRoll):
                                strings.tellString(target, 'playerrolled', {'name':player.name, 'roll':rollStrings.getString(userid, callbacks[callback] + ':name', {})})

                else:
                    fireEvent('player_roll_fail', {'userid':userid})
                    for target in players:
                        if userid == target:
                            strings.tellString(userid, 'failrolled', {})
                            playsound(userid, 'buttons/button11.wav', 1.0)

                        else:
                            if int(announceFail):
                                strings.tellString(target, 'playerfailed', {'name':player.name})

            else:
                strings.tellString(userid, 'maxreached', {'max':rollAmount})

        else:
            strings.tellString(userid, 'isdead', {})

    else:
        strings.tellString(userid, 'unable', {})

def infoCallback(userid, args):
    createMenu(userid)

def createMenu(userid):
    popup = easymenu('_superdice_info_' + str(userid), None, popupCallback)
    popup.c_titleformat = strings.getString(userid, 'infomenu', {'version':info.version})
    popup.c_beginsep = ' \n '
    popup.c_pagesep = ' \n '
    count = 0
    for callback in sorted(callbacks.keys(), key=lambda roll: rollStrings.getString(userid, callbacks[roll] + ':name', {})):
        count += 1
        popup.addoption((rollStrings.getString(userid, callbacks[callback] + ':name', {}), rollStrings.getString(userid, callbacks[callback] + ':desc', {})), rollStrings.getString(userid, callbacks[callback] + ':name', {}) + ' [' + str(count) + ']')

    popup.send(userid)

def popupCallback(userid, choice, popup):
    playsound(userid, 'UI/buttonclick.wav', 1.0)
    strings.tellString(userid, 'description', {'roll':choice[0], 'description':choice[1]})
    createMenu(userid)

# ----
# Events
# ----
def es_map_start(ev):
    loadevents('addons/eventscripts/superdice/data/events.res')
    players.clear()
    configData.execute()

def player_disconnect(ev):
    userid = ev['userid']
    if not userid in players:
        return

    del players[userid]

def player_spawn(ev):
    players[ev['userid']]['rolls'] = 0

# ----
# Unload
# ----
def unload():
    unregisterClientCommand('+ability')
    unregisterClientCommand('-ability')
    for command in rollCommands:
        if not exists('saycommand', command):
            continue
        unregisterSayCommand(command)

    for command in infoCommands:
        if not exists('saycommand', command):
            continue
        unregisterSayCommand(command)

    if addons:
        for addon in addons:
            sunload('superdice/addons/' + addon)

    if rolls:
        for roll in rolls:
            sunload('superdice/rolls/' + roll)

# ----
# Init/Load
# ----
configData = configFile('superdice')
rollCommands = str(configData.cvar('superdice_cfg_rollcommands', '!rtd,rtd,rollthedice,!rollthedice,superdice,!superdice', 'What commands are used for a player to roll the dice?')).split(',')
rollAmount = configData.cvar('superdice_cfg_rollamount', 1, 'How many times can a player roll the dice per spawn?')
rollFail = configData.cvar('superdice_cfg_failchance', 10, 'What is the chance of failing a roll?')
infoCommands = str(configData.cvar('superdice_cfg_infocommands', '!rolls,rolls,rtdhelp,!rtdhelp,!rollinfo,rollinfo,superdicehelp,!superdicehelp', 'What commands are used for a player to get the rolls info menu?')).split(',')
announceRoll = configData.cvar('superdice_cfg_announceroll', 1, 'Should SuperDice announce to the players that a player rolled?')
announceFail = configData.cvar('superdice_cfg_announcefail', 1, 'Should SuperDice announce to the players that a player failed to roll?')
configData.write()
configData.execute()

callbacks = {}

acallbacks = {'plus':set(), 'minus':set()}

registerClientCommand('+ability', plusAbilityCallback, 'Ability command for players used by SuperDice.')
registerClientCommand('-ability', minusAbilityCallback, 'Ability command for players used by SuperDice.')

strings = stringsManager('languages')

rollStrings = stringsManager('rollstrings')

for command in rollCommands:
    if exists('saycommand', command):
        continue
    registerSayCommand(command, rollCallback, 'Roll the dice commands for players used by SuperDice.')

for command in infoCommands:
    if exists('saycommand', command):
        continue
    registerSayCommand(command, infoCallback, 'Rolls info menu commands for players used by SuperDice.')

addons = readData('addonloaddata')
if addons:
    for addon in addons:
        sload('superdice/addons/' + addon)

rolls = readData('diceloaddata')
if rolls:
    for roll in rolls:
        sload('superdice/rolls/' + roll)

loadevents('declare', 'addons/eventscripts/superdice/data/events.res')
loadevents('addons/eventscripts/superdice/data/events.res')

ServerVar('superdice_ver', info.version, 'SuperDice\'s Version Number').makepublic()
rollAmount.makepublic()
